
#include <windows.h>
#include <atlcomcli.h>
#include "CDXTexture3D.h"
#include "CReleaseMacro.h"
//////////Texture Base////////////
CDXTexture3D::CDXTexture3D(CDXDevice* pDevice) : CDXResource(pDevice)
{
	m_pTexture = NULL;

}
CDXTexture3D::~CDXTexture3D()
{
	ReleaseResources();
}
HRESULT CDXTexture3D::ReleaseResources()
{
	SAFE_RELEASE(m_pTexture);
	return __super::ReleaseResources();
}

ID3D11Texture3D* CDXTexture3D::GetD3D11Texture3D()
{
	return m_pTexture;
}

HRESULT CDXTexture3D::Create(D3D11_TEXTURE3D_DESC* pDesc, D3D11_SUBRESOURCE_DATA* pInitData)
{
	if (m_pDevice == NULL)
		return E_FAIL;
	ReleaseResources();

	HRESULT hr = S_OK;
	ID3D11Device* pDX11Device = m_pDevice->GetD3D11Device();
	hr = pDX11Device->CreateTexture3D( pDesc, pInitData, &m_pTexture );
	return hr;
}

HRESULT CDXTexture3D::OpenShareHandle(HANDLE hResource)
{
	if (m_pDevice == NULL)
		return E_FAIL;
	if (hResource == 0)
		return E_INVALIDARG;
	if (hResource == m_hShareHandle)
	{
		return S_OK;
	}
	HRESULT hr = S_OK;
	hr = ReleaseResources();
	CComPtr<ID3D11Resource> pResource = NULL;
	ID3D11Device* pDX11Device = m_pDevice->GetD3D11Device();
	hr = pDX11Device->OpenSharedResource(hResource, __uuidof(ID3D11Resource), (void**)(&pResource)); 
	if (FAILED(hr))
		return hr;
	hr = pResource->QueryInterface(__uuidof(ID3D11Texture3D), (void**)(&m_pTexture)); 
	if (FAILED(hr))
		return hr; 
	m_hShareHandle = hResource;
	return S_OK;
}
HRESULT CDXTexture3D::SaveToFile(LPCWSTR path)
{
	HRESULT hr = S_OK;
	if (m_pTexture == NULL || m_pDevice == NULL)
		return E_FAIL;

	WCHAR mPath[MAX_PATH] = {0};
	WCHAR fExt[MAX_PATH] = {0};
	const WCHAR* tmpfExt = wcsrchr(path, L'.');

	D3DX11_IMAGE_FILE_FORMAT fmt;

	if (tmpfExt == NULL)
	{
		swprintf_s(fExt, MAX_PATH, L"dds");
		swprintf_s(mPath, MAX_PATH, L"%s.%s", path, fExt);
		_wcslwr_s(fExt, MAX_PATH);
		_wcslwr_s(mPath, MAX_PATH);

	}
	else
	{
		wcscpy_s(fExt, MAX_PATH, &(tmpfExt[1]));
		wcscpy_s(mPath, MAX_PATH, path);
		_wcslwr_s(fExt, MAX_PATH);
		_wcslwr_s(mPath, MAX_PATH);
	}

	if (wcscmp(fExt, L"png") == 0)
	{
		fmt = D3DX11_IFF_PNG;
	}
	else if (wcscmp(fExt, L"bmp") == 0)
	{
		fmt = D3DX11_IFF_BMP;
	}
	else if (wcscmp(fExt, L"jpg") == 0)
	{
		fmt = D3DX11_IFF_JPG;
	}
	else if (wcscmp(fExt, L"tif") == 0)
	{
		fmt = D3DX11_IFF_TIFF;
	}
	else if (wcscmp(fExt, L"gif") == 0)
	{
		fmt = D3DX11_IFF_GIF;
	}
	else if (wcscmp(fExt, L"wmp") == 0)
	{
		fmt = D3DX11_IFF_WMP;
	}
	else if (wcscmp(fExt, L"dds") == 0)
	{
		fmt = D3DX11_IFF_DDS;
	}
	else
	{
		return E_FAIL;
	}
	ID3D11DeviceContext* pContext = m_pDevice->GetD3D11DeviceContext();
	hr = D3DX11SaveTextureToFile(pContext, m_pTexture, fmt, path);
	return hr;
}

HRESULT CDXTexture3D::LoadFromFile(LPCWSTR path, D3DX11_IMAGE_LOAD_INFO* pImageInfo)
{
	if (m_pDevice == NULL)
		return E_FAIL;

	HRESULT hr = S_OK;
	hr = ReleaseResources();
	ID3D11Device* pDX11Device = m_pDevice->GetD3D11Device();
	hr = D3DX11CreateTextureFromFile(pDX11Device, path, pImageInfo, NULL, (ID3D11Resource**)&m_pTexture, NULL);

	return hr;
}
HRESULT CDXTexture3D::Resize(UINT width, UINT height, UINT depth)
{
	if (m_pTexture == NULL || m_pDevice == NULL)
		return E_FAIL;
	if (width <=0 || height <= 0)
		return E_FAIL;

	HRESULT hr = S_OK;
	D3D11_TEXTURE3D_DESC oldDesc;
	m_pTexture->GetDesc(&oldDesc);
	if (oldDesc.Width == width && oldDesc.Height == height && oldDesc.Depth == depth)
		return S_OK;
	D3D11_TEXTURE3D_DESC newDesc = oldDesc;
	newDesc.Width = width;
	newDesc.Height = height;
	ID3D11Texture3D *pTexture = NULL;
	ID3D11Device* pDX11Device = m_pDevice->GetD3D11Device();
	ID3D11DeviceContext* pContext = m_pDevice->GetD3D11DeviceContext();
	hr = pDX11Device->CreateTexture3D( &newDesc, NULL, &pTexture);
	if (FAILED(hr))
		return hr;

	hr = D3DX11LoadTextureFromTexture(pContext, m_pTexture, NULL, pTexture);
	if (FAILED(hr))
		return hr;
	ReleaseResources();
	m_pTexture = pTexture;

	return hr;
}

ID3D11Resource* CDXTexture3D::GetResource() const
{
	return (ID3D11Resource*)m_pTexture;
}

HRESULT CDXTexture3D::GetDesc(D3D11_TEXTURE3D_DESC* pOutDesc)
{
	if (pOutDesc == NULL || m_pTexture == NULL)
		return E_FAIL;
	m_pTexture->GetDesc(pOutDesc);
	return S_OK;
}
HRESULT CDXTexture3D::GetShaderResourceView(DXGI_FORMAT fmt, UINT MostDetailedMip, UINT MipLevels, ID3D11ShaderResourceView** ppShaderResourceView)
{
	HRESULT hr = S_OK;
	D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc = {fmt, D3D11_SRV_DIMENSION_TEXTURE3D, {MostDetailedMip, MipLevels} };
	hr = GetShaderResourceView(&SRVDesc, ppShaderResourceView);	
	return hr;
}

HRESULT CDXTexture3D::GetUnorderedAccessView(DXGI_FORMAT fmt, UINT MipSlice, UINT FirstWSlice, UINT WSize, ID3D11UnorderedAccessView** ppUnorderAccessView)
{
	HRESULT hr = S_OK;
	D3D11_UNORDERED_ACCESS_VIEW_DESC UAVDesc = {fmt, D3D11_UAV_DIMENSION_TEXTURE3D, {MipSlice, FirstWSlice, WSize}};
	hr = GetUnorderedAccessView(&UAVDesc, ppUnorderAccessView);
	return hr;
}

HRESULT CDXTexture3D::GetRenderTargetView(DXGI_FORMAT fmt, UINT MipSlice, UINT FirstWSlice, UINT WSize, ID3D11RenderTargetView** ppRenderTargetView)
{
	HRESULT hr = S_OK;
	D3D11_TEX3D_RTV tex3dRTV = {MipSlice, FirstWSlice, WSize};
	D3D11_RENDER_TARGET_VIEW_DESC RTVDesc;
	RTVDesc.Format = fmt;
	RTVDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE3D;
	RTVDesc.Texture3D = tex3dRTV;
	hr = GetRenderTargetView(&RTVDesc, ppRenderTargetView);
	return hr;
}